class Camera {

    constructor(xOffset = 0, yOffset = 0) {
        this.xOffset = xOffset;
        this.yOffset = yOffset;
    }

    /**
     * 
     * @param {int} x 物体在世界坐标中的x值
     * @returns 物体在画板坐标中的x值
     */
    getCanvasX(x) {
        return x - this.xOffset;
    }

    /**
     * 
     * @param {int} y 物体在世界坐标中的y值
     * @returns 物体在画板坐标中的y值
     */
    getCanvasY(y) {
        return y - this.yOffset - 40;   // 减去的40是上面topbar的高度
    }

    /**
     * 
     * @param {int} x 物体在画板坐标中的x值
     * @returns 物体在世界坐标中的x值
     */
    getWorldX(x) {
        return x + this.xOffset;
    }

    /**
     * 
     * @param {int} y 物体在画板坐标中的y值
     * @returns 物体在世界坐标中的y值
     */
    getWorldY(y) {
        return y + this.yOffset;
    }

    setPos(x, y) {
        this.xOffset = x;
        this.yOffset = y;
    }

    /**
     * 为了减少代码量和运算量，这个函数能直接通过差值使摄像机移动一段距离
     * @param {int} xDis
     * @param {int} yDis
     */
    move(xDis, yDis) {
        this.xOffset += xDis;
        this.yOffset += yDis;
    }

    /**
     * 程序渲染的入口，在此调用窗口内所有物体的渲染
     */
    render() {
        // 先清空画布
        ctx.clearRect(0, 0, cvs.width, cvs.height);
        // 画节点
        for (const node of nodes) {
            node.draw();
        }
        // 画线
        for (const line of lines) {
            line.draw();
        }
        // 新建节点菜单
        _createMenu.draw();
        // 编辑节点菜单，由于可能为空，所以要先判断再执行函数
        if (_editMenu != null) {
            _editMenu.draw();
        }
        // 最后再调用一遍自己，实现循环调用
        requestAnimationFrame(camera.render);
    }
}